改一行 prompt 後分數掉了三個百分點,先確認前後兩批納入相同的趟數,再讓兩個版本同時開跑、各跑兩批,差距要大過同一個 prompt 自己兩批的差距,兩組方向也要一致,才算改動造成的;照這個步驟判,刪掉一行指示讓 recall 真的掉了約 5 個百分點。
需求釐清 agent 在整理 ticket 時,會把驗收條件 AC 裡的問題記在 AC 標註區塊,另有 Goal 記目標,Scope in、Scope out 分別記做與不做的範圍。system prompt 對 AC 檢查有一句指示,改 prompt 時很容易被順手收短或刪掉(原文第 9 行):
每一條 AC 對三類問題各檢查一次
之前只拿那張優惠碼的卡對照過一次。原版與刪掉這一行的變體各跑三次,人工標好的 4 個標註三次合計 12 個,原版標到 8 個、變體 5 個,看起來刪掉就會漏標;但那只是一筆 case、一組前後對照,看不出同一個 prompt 再跑一次會不會也差這麼多。
2026-09-30 把整份 dataset 16 筆、每筆 k=5(k 是同一筆 case 重跑的次數),原版 cd590b9ba593 跑了 A1、A2 兩批,刪一行版 64ab4d919668 跑了 B1、B2 兩批。模型是 gpt-5.4-mini,外部查詢使用 fixture 重播模式,fixture 用來保存工具的請求與回應。
重跑整份 dataset 的命令 run-all 為這次加了 --prompt 旗標,讀進指定的檔案當 system prompt,並在每批目錄存一份 prompt.txt(src/cli/run-all.ts 第 17–32 行節錄):
const promptFlag = argv.indexOf('--prompt');
const systemPrompt =
promptFlag === -1 ? undefined : readFileSync(String(argv[promptFlag + 1]), 'utf8');
const version = promptVersion(systemPrompt);
// ...
writeFileSync(join(batchDir, 'prompt.txt'), systemPrompt ?? SYSTEM_PROMPT);
四批的 prompt.txt 逐字比對,只差上面那一句,刪一行版就是 prompts/no-per-ac-check.txt。B1 與 A1 同時開跑,B2 與 A2 同時開跑,兩組相隔約 5 分鐘。
precision 是 agent 標的有幾成是對的,recall 是人工標好的有幾成被找到,單位都是條號加類別。多標是 agent 標了、人工沒標,漏標是人工標了、agent 沒找到。
每筆 case 的 goal state 記下事先寫好的通過條件,判定程式 scorer 逐個檢查最終卡片的受評欄位,全部符合,這筆 case 才通過。pass^5 則看 16 筆裡,有幾筆收齊 5 次判定且次次通過:
| 批次 | prompt | 完成/預定 | 通過趟數 | pass^5 | 對上/多標/漏標 | precision | recall |
|---|---|---|---|---|---|---|---|
| A1 | 原版 | 77/80 | 1 | 0/16 | 90/201/42 | 30.93% | 68.18% |
| A2 | 原版 | 77/80 | 2 | 0/16 | 95/204/36 | 31.77% | 72.52% |
| B1 | 刪一行 | 78/80 | 6 | 0/16 | 103/148/29 | 41.04% | 78.03% |
| B2 | 刪一行 | 76/80 | 13 | 1/16 | 101/142/32 | 41.56% | 75.94% |
這次對照的紀錄保留了這四批資料。四批都沒跑滿,所以先核對缺趟。
每批預定 80 趟,缺的落在不同的 case:
missing-context-001 1 趟、missing-context-002 2 趟missing-context-003 2 趟、noise-over-signal-002 1 趟merged-concerns-001、missing-context-001 各 1 趟merged-concerns-001 1 趟、merged-concerns-003 3 趟四批都寫出了總表,而 run-all 的迴圈只容許 MissingFixtureError,遇到其他錯誤整批就會中止、不寫總表,所以缺的趟數都停在 fixture 對不上。fixture 的鍵是工具名加參數,agent 送出錄製時沒出現過的組合,那一趟就中斷,不進 precision 與 recall 的分母。
catch 原本只在終端機輸出一行,缺的那趟不留檔,所以這四批先不拿來比。16 份 fixture 都沒有錄到任何查詢,錄製時的外部回答又是本機寫死、不看參數的一句話,缺的那幾趟其實只是 agent 多查了一次資料。
run-all 因此再加一個 --fill-missing,對不上的查詢照樣拿到那句固定回答,agent 看到的內容不會變,補了哪幾筆寫進該趟的 fixture-filled.json;沒開這個旗標時,停下的那趟也會留一份 fixture-miss.json。當天晚上照同一個規格重跑,每個版本兩批、k=5,四批都是 80/80:
| 批次 | prompt | 完成/預定 | 補齊的趟數 | 通過趟數 | pass^5 | 對上/多標/漏標 | precision | recall |
|---|---|---|---|---|---|---|---|---|
| A3 | 原版 | 80/80 | 5 | 5 | 0/16 | 105/200/30 | 34.43% | 77.78% |
| B3 | 刪一行 | 80/80 | 2 | 8 | 0/16 | 99/157/36 | 38.67% | 73.33% |
| A4 | 原版 | 80/80 | 4 | 4 | 0/16 | 106/207/29 | 33.87% | 78.52% |
| B4 | 刪一行 | 80/80 | 0 | 4 | 0/16 | 99/180/36 | 35.48% | 73.33% |
表裡上下相鄰的兩批是一組配對,A3 與 B3 同時開跑,B4 比 A4 早 16 秒開跑。
早上的 A1 與 A2 開跑相差約 5 分鐘,recall 是 90/132 與 95/131,相差約 4.34 個百分點,但這個差值混著缺趟位置不同的影響。晚上分母一樣之後,原版 A3 與 A4 的 recall 是 105/135 與 106/135,只差 0.74 點;刪一行的 B3 與 B4 都是 99/135,差 0。precision 原版兩批差 0.56 點,刪一行兩批差 3.19 點。
同一個原版,早上兩批的 recall 是 68.18% 與 72.52%,晚上是 77.78% 與 78.52%,差了將近 10 點。幾分鐘內的兩批很接近,隔幾個小時的兩批卻會整體移動,所以兩個版本要同時開跑、成對比較。拿早上的原版去比晚上的變體,差距裡就混著時段。
09-16 那批同樣是原版,precision 34%、recall 78%,但那批每筆 k=3,有 12 筆是當批才錄 fixture,兩週間模型端有沒有變也無從得知,只能當跑分歷史,不拿來估計這次對照的起伏。
晚上兩組配對,刪一行版的 recall 分別低 4.45 與 5.19 個百分點,兩組方向相同,而且都比兩個版本各自兩批之間的差距大。漏標從原版的 30、29 個,增加到兩批都是 36 個。這一項判定為刪掉那一行造成的,是真的變差。
precision 刪一行版分別高 4.24 與 1.61 個百分點,方向相同,但第二組的 1.61 點比刪一行版自己兩批的 3.19 點還小,這一項判不出來,只能當雜訊。
早上那兩組配對看到的是 precision 高約 10 點、recall 也比較高,方向跟晚上相反。那四批的分母不同,本來就不該拿來判定;補齊之後,整份 dataset 的結果和先前單張優惠碼卡看到的漏標方向一致。
每趟判定寫在 score.json 的 pass,晚上四批通過的趟數是 5、8、4、4,pass^5 全是 0/16,兩個版本都沒達到 16/16 的結果門檻。recall 不掉破七成是診斷界線,刪一行版的 73.33% 還在界線上,卻已經比原版少了約 5 點;診斷界線沒破,不代表這次改動沒有讓它變差。
八批的 trajectory.json 每批約 17 到 18 萬 input、2.7 到 3.1 萬 output token,依 2026-09-29 的 gpt-5.4-mini Standard 單價、input 全按原價換算,每批上限約 US$0.25 到 0.28。model.json 的起訖每批約 4 分半到 5 分鐘,這次前後對照總共跑了八批。
改一行 prompt 之後分數有變,先補齊缺趟,再讓兩個版本同時開跑、各跑兩批,差距要大過同一個 prompt 自己兩批的差距,兩組方向也要一致。照這個步驟,刪掉「每一條 AC 對三類問題各檢查一次」讓 recall 掉了約 5 個百分點,是真的變差;precision 的升幅判不出來;早上的缺趟是 fixture 沒補齊,根本不是抖動。
兩個版本的 pass^5 都是 0/16,這次判的是改動有沒有讓它變差,離能不能上線還很遠。同一個 prompt 隔幾個小時會整體移動將近 10 點,兩批量到的只是同時開跑時的差距,換個時段比較就要重新量。